package com.ude.pim.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ude.pim.common.CustomException;
import com.ude.pim.common.R;
import com.ude.pim.dto.CaseSubDTO;
import com.ude.pim.dto.CaseSubQueryDTO;
import com.ude.pim.entity.*;
import com.ude.pim.mapper.CaseSubMapper;
import com.ude.pim.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yb
 * @since 2023-08-08
 */
@Service
@Lazy
public class CaseSubServiceImpl extends ServiceImpl<CaseSubMapper, CaseSub> implements CaseSubService {
    @Autowired
    private UserService userService;

    @Autowired
    private CaseSubUserService CaseSubUserService;

    @Autowired
    private SubService subService;

    @Autowired
    private CaseService caseService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public R<List<CaseSub>> page(CaseSubQueryDTO caseSubQueryDTO) {
        return null;
    }

    /**
     * 2. 根据用户id在关联关系表中查询到负责的专案子流程id
     * 3. 根据专案子流程id查询到对应的专案子流程信息
     * @param chargeId
     * @return
     */
    @Override
    public R<List<CaseSubDTO>> getByChargeId(Long chargeId) {
        // 2. 根据用户id在关联关系表中查询到负责的专案子流程集合
        List<CaseSubUser> list = CaseSubUserService.list(new LambdaQueryWrapper<CaseSubUser>().eq(CaseSubUser::getUserId, chargeId));

        // 3. 根据专案子流程集合获取到其中元素对应的专案子流程id，查询到对应的专案子流程信息
        List<CaseSub> subList = list.stream().map(s -> this.getById(s.getCaseSubId())).collect(Collectors.toList());
        List<CaseSubDTO> caseSubDTOList = subList.stream().filter(s->
                //只获取还没完成的
                s.getFinishTime() == null && s.getStartTime()!=null
        ).map(s -> {

            CaseSubDTO caseSubDTO = new CaseSubDTO();
            BeanUtils.copyProperties(s, caseSubDTO);

            //获得子流程的名称
            R<String> r = subService.getNameById(s.getSubId());
            caseSubDTO.setSubName(r.getData());

            //获得父流程的名称
            r = caseService.getNameById(s.getCaseId());
            caseSubDTO.setCaseName(r.getData());

            return caseSubDTO;
        }).collect(Collectors.toList());
        return R.success(caseSubDTOList);
    }

    /**
     * 1. 获取到所有专案子流程
     * 2. 通过专案子流程对象中的subId数据查到子流程名称
     * 3. 通过专案子流程对象中的caseId数据查到专案名称
     * 4. 通过专案子流程id查询到负责人id
     * 5. 返回专案子流程DTO列表
     * @return
     */
    @Override
    public R<List<CaseSubDTO>> getList() {
        //1. 获取到所有专案子流程
        List<CaseSub> list = this.list();
        List<CaseSubDTO> caseSubDTOS = list.stream().map(s -> {
            CaseSubDTO caseSubDTO = new CaseSubDTO();
            BeanUtils.copyProperties(s, caseSubDTO);

            //2. 通过专案子流程对象中的subId数据查到子流程名称
            R<String> r = subService.getNameById(s.getSubId());
            caseSubDTO.setSubName(r.getData());

            // 3. 通过专案子流程对象中的caseId数据查到专案名称
            Long caseId = s.getCaseId();
            Case caseObject = caseService.getById(caseId);
            caseSubDTO.setCaseName(caseObject.getName());

            return caseSubDTO;
        }).collect(Collectors.toList());

        return R.success(caseSubDTOS);
    }

    /**
     * 1. 获取到所有专案子流程
     * 2. 通过专案子流程对象中的subId数据查到子流程名称
     * 3. 通过专案子流程id查询到负责人id，进而查询到姓名
     * 4. 返回专案子流程DTO列表
     * @return
     */
    @Override
    public R<List<CaseSubDTO>> getByCaseId(Long caseId) {
        String key = "caseSub:list:"+caseId;
        String caseSubJSON = stringRedisTemplate.opsForValue().get(key);
        if(StringUtils.isNotBlank(caseSubJSON)){
            List<CaseSubDTO> caseSubDTOS = JSONUtil.toList(caseSubJSON, CaseSubDTO.class);
            return R.success(caseSubDTOS);
        }

        //没有则重建缓存

        List<CaseSub> list = this.list(new LambdaQueryWrapper<CaseSub>().eq(CaseSub::getCaseId, caseId));
        List<CaseSubDTO> caseSubDTOS = list.stream().map(s -> {
            CaseSubDTO caseSubDTO = new CaseSubDTO();
            BeanUtils.copyProperties(s, caseSubDTO);

            //2. 通过专案子流程对象中的subId数据查到子流程名称
            Integer subId = s.getSubId();
            Sub sub = subService.getById(subId);
            caseSubDTO.setSubName(sub.getName());

            //3. 通过专案子流程id查询到负责人id，进而查询到姓名
            List<CaseSubUser> user = CaseSubUserService.list(new LambdaQueryWrapper<CaseSubUser>().eq(CaseSubUser::getCaseSubId,s.getId()));
            if (user != null) {
                List<String> chargeName = user.stream().map(k -> userService.getById(k.getUserId()).getName()).collect(Collectors.toList());
                List<Long> chargeId = user.stream().map(k -> k.getUserId()).collect(Collectors.toList());
                caseSubDTO.setChargeName(chargeName);
                caseSubDTO.setChargeId(chargeId);
            }

            return caseSubDTO;
        }).collect(Collectors.toList());

        //写入缓存
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(caseSubDTOS));

        return R.success(caseSubDTOS);
    }

    //根据子流程信息的专案ID获取专案名称
    public String getCaseName(Long caseId){
        R<String> name = caseService.getNameById(caseId);
        return name.getData();
    }

    //根据子流程信息的子流程ID获取子流程名称
    public String getSubName(Integer subId){
        R<String> name = subService.getNameById(subId);
        return name.getData();
    }

    //给特定id添加指定的外界因素延期
    public Boolean addUnforcedDays(Long id,Integer days){
        CaseSub caseSub = this.getById(id);
        //没有该id
        if (caseSub == null) {
            return false;
        }
        Integer unforcedDays = caseSub.getUnforcedDays();
        //如果对象为空则置为0
        unforcedDays=unforcedDays==null?0:unforcedDays;
        unforcedDays+=days;
        caseSub.setUnforcedDays(unforcedDays);
        this.updateById(caseSub);
        return true;
    }

    //给特定id添加指定的人为因素延期
    public Boolean addApplyDelay(Long id, Integer days){
        CaseSub caseSub = this.getById(id);
        if (caseSub == null) {
            return false;
        }
        Integer applyDelay = caseSub.getApplyDelay();
        applyDelay=applyDelay==null?0:applyDelay;
        applyDelay+=days;
        caseSub.setApplyDelay(applyDelay);
        this.updateById(caseSub);
        return true;
    }


    /**
     * 获取预计完成时间
     * 1. 开始时间
     * 2. 开始时间+计划天数
     * 3. 开始时间+外界因素延期
     * 4. +人为因素延期
     * @param id
     * @return
     */
    @Override
    public LocalDateTime getPredictTime(Long id) {
        CaseSub caseSub = this.getById(id);
        LocalDateTime startTime = caseSub.getStartTime();
        //加上计划时间
        LocalDateTime predictTime = startTime.plusDays(caseSub.getPlanDays());
        //加上外界因素延期
        Integer unforcedDays = caseSub.getUnforcedDays();
        predictTime = predictTime.plusDays(unforcedDays==null?0:unforcedDays);
        //加上人为因素延期
        Integer applyDelay = caseSub.getApplyDelay();
        predictTime = predictTime.plusDays(applyDelay==null?0:applyDelay);
        return predictTime;
    }

    @Override
    public Boolean setFinish(Long id, LocalDateTime t) {
        CaseSub caseSub = this.getById(id);
        caseSub.setFinishTime(t);
        this.save(caseSub);
        return true;
    }


    /** 搁置状态....
     * 1. 上一个阶段完结，下一个阶段常规来说自动开始
     * 2. 首先判断是否有负责人，如果没有负责人，则冻结阶段
     * 3. 如果有负责人，且是常规阶段，则自动开始
     * 4. 如果是特殊阶段，比如出图完就要开始配电
     */

    @Override
    public void startNext(Long caseSubId) {
        CaseSub caseSub = this.getById(caseSubId);
        Long caseId = caseSub.getCaseId();
        LambdaQueryWrapper<CaseSub> lqw = new LambdaQueryWrapper<>();
        lqw.eq(CaseSub::getCaseId,caseId);
        lqw.orderByAsc(CaseSub::getSubId);
        List<CaseSub> list = this.list(lqw);
        int index = list.indexOf(caseSub);
        if(index==-1)
            throw new CustomException("不存在该子阶段");
        //已经是最后一个，则不做处理
        if(index==list.size()-1)
            return;
        for (int i = index+1; i < list.size(); i++) {
            CaseSub tmp = list.get(i);
            //有并行的情况，所以下个阶段可能正在执行
            if(tmp.getStartTime()!=null)
                continue;
            tmp.setCreateTime(LocalDateTime.now());
            this.save(tmp);
            return;
        }
    }
}
